/**
 * NJS
 *
 * $Id: njs.js 6 2011-07-12 08:32:51Z leizongmin@gmail.com $
 * @author 老雷 <leizongmin@gmail.com>
 * @version 0.22
 * @date 2011-07-12 2011-07-12 13:56:12
 */
 
var fs		= require('fs'),
	url		= require('url'),
	os		= require('os'),
	querystring = require('querystring'),
	path	= require('path'),
	config	= require('./config'),
	njsvm	= require('./njsvm'),
	logger	= require('./logger');
 
 
/** njs命名空间 */
var njs = {};

/** NJS版本 */
var cpus = os.cpus();
var NJS_VERSION = 'njs/0.21 (nodejs/' + process.version + '; ' + os.type() + '; ' + cpus[0].model + ' * ' + cpus.length + ')';
logger.log(NJS_VERSION);
 
/** 解析客户请求 */
njs.request = function (request, response) {
	
	// 如果是POST请求，则获取POST提交的数据，读取完成后会触发session的post事件
	// 必须在请求开始时就监听data事件，否则会丢失部分数据
	if (request.method.toLowerCase() == 'post') {
	
		request._post = {
					chunk: new Buffer(1024 * 8),
					dataSize: 0
				}
		
		request.on('data', function (chunk) {
			logger.log('recive data: ' + (chunk.length / 1024) + 'KB', 'Post-Data');
			var post = request._post;
			
			// 限制上传数据的大小
			if (post.dataSize + chunk.length > config.get(request.headers.host, 'upload-size')) {
				request._post_ready = false;
				request.emit('_post_ready');
				logger.log('recive data out of upload-size!', 'Post-Data');
				return;
			}
			
			if (post.dataSize + chunk.length >= post.chunk.length) {
				var newChunk = new Buffer(post.chunk.length * 3);
				post.chunk.copy(newChunk, 0, 0);
				post.chunk = newChunk;
			}
			
			chunk.copy(post.chunk, post.dataSize, 0);
			post.dataSize += chunk.length;
		});
		
		request.on('end', function () {
			njs.parsePostData(request);
			
			logger.log('recive data finish!', 'Post-Data');
			// logger.dump(request._post.chunk);
		});
	}

	// 获取请求主机名
	var host = request.headers['host'];													// 主机名
	var requrl = url.parse(request.url);
	var GET = querystring.parse(requrl.query);											// GET变量
	request.GET = GET;
	
	var filename = path.resolve(config.get(host, 'path'), requrl.pathname.substr(1));	// 请求的文件名
	
	response.setHeader('Server', NJS_VERSION);										// NJS版本
	njs.parseRequest(host, filename, request, response);
}

njs.parseRequest = function (host, filename, request, response) {

	// 检查文件是否存在，或者是否为目录，是目录则自动加上可用的首页文件名
	fs.stat(filename, function (err, stats) {
		// 文件不存在
		if (err) {
			njs.responseError(response, 404, err.stack);
		}
		// 是文件，判断是普通文件还是可执行js文件
		else if (stats.isFile()) {
			
			var extname = path.extname(filename).substr(1).toLowerCase();
			var basename = path.basename(filename, 'js');
			
			var type = config.get(host, 'content-type');
			if (extname in type) {
				response.setHeader('Content-Type', type[extname]);
			}
			
			if (extname == 'js' && basename.substr(0, 1) == '$') {
				njs.requestNjs(host, filename, request, response);
			}
			else {
				njs.requestFile(host, filename, request, response);
			}
		
		}
		// 是目录
		else {
			filename = path.resolve(filename, config.get(host, 'default-page'));
			njs.parseRequest(host, filename, request, response);
		}
	});
}

// 返回出错信息
njs.responseError = function (response, code, err) {
	response.statusCode = code;
	response.end(err);
}

// 请求普通的文件
njs.requestFile = function (host, filename, request, response) {
	logger.log(host + ' ' + filename, request.method);
	
	fs.readFile(filename, function (err, data) {
		if (err) {
			njs.responseError(response, 500, err.stack);
		}
		else {
			response.end(data);
		}
	});
}

njs.requestNjs = function (host, filename, request, response) {
	logger.log(host + ' [NJS] ' + filename, request.method);
	response.setHeader('Content-Type', 'text/html');
	
	// 创建session实例
	session = new njsvm.Session();
	// 创建njs实例
	instance = njsvm.newInstance(filename, session, request, response);
	
	// 如果创建njs实例失败，则返回字符串描述的错误信息
	if (typeof instance == 'string') {
		response.end(instance);
	}
	
	else {
		logger.log(session.timestamp + ' start:', 'NJSVM');
		
		// 配置request
		if (!request.POST) {
			request.POST = {};
		}
		if (!request.FILE) {
			request.FILE = {};
		}
		
		// 配置session环境
		session.host = host;
		session.filename = filename;
		session.dirname = path.dirname(filename);
		session.on('end', function () {
			logger.log(session.timestamp + ' end, spent ' + (new Date().getTime() - session.timestamp) + 'ms.', 'NJSVM');
		});
		
		// 调用session的start事件
		session.emit('start');
		
		// 如果是POST方式提交数据，当处理完上传的数据时，还好触发post事件
		if (request.method.toLowerCase() == 'post') {
			if (request._post_ready) {
				session.emit('post');
			}
			else {
				request.on('_post_ready', function () {
					session.emit('post');
				});
			}
		}
	}
}

njs.parsePostData = function (request) {
	var chunk = new Buffer(request._post.dataSize);
	request._post.chunk.copy(chunk, 0, 0, request._post.dataSize);
	delete request._post;
	
	// 检查是否为上传文件
	var content_type = request.headers['content-type'].trim();
	if (content_type.substr(0, 20) == 'multipart/form-data;') {
		request.FILE = {};
		request.POST = {};
		
		// 解析POST数据
		var boundary = '--' + content_type.substr(20).trim().substr(9).trim();
		chunk = chunk.slice(boundary.length + 2, chunk.length - boundary.length - 4); 
		var chunkString = chunk.toString();
		chunk = undefined;	// 释放空间
		
		// 分开各个参数
		var dataArray = chunkString.split(boundary + '\r\n');
		chunkString = undefined;  // 释放空间
		// logger.dump(dataArray);
		for (i in dataArray) {
			var param = dataArray[i];
			var paramHeaderEnd = param.indexOf('\r\n\r\n');
			var paramHeaders = param.substr(0, paramHeaderEnd).split('\r\n');	// 数据类型描述
			var paramData = param.substr(paramHeaderEnd + 4);					// 数据
			paramData = paramData.substr(0, paramData.length - 2);
			// logger.dump(paramHeaders);
			
			var headers = paramHeaders[0].substr(20).split(';');
			// logger.dump(headers);
			for (j in headers) {
				headers[j] = headers[j].trim();
			}
			var paramName = headers[1].substr(6, headers[1].length - 7);
			// logger.dump(paramName);
			
			if (paramHeaders.length < 2) {
				request.POST[paramName] = paramData;
			}
			
			else {
				var paramFileName = headers[2].substr(10, headers[2].length - 11);
				request.FILE[paramName] = {
					filename: paramFileName,
					data: paramData
				}
			}
		}
		// logger.dump(request.POST, 'POST');
		// logger.dump(request.FILE, 'FILE');
	}
	
	// 跟GET格式一样的：
	else {
		request.POST = querystring.parse(chunk.toString());
	}
	
	// 解析完成，设置一个标记
	request._post_ready = true;
	request.emit('_post_ready');
}

/** 模块输出 */
exports.request = njs.request;